package jmind.core.http;

import jmind.base.algo.atomic.StatsCounter;
import jmind.base.lang.Pair;
import jmind.base.lang.Record;
import jmind.base.util.DataUtil;
import jmind.base.util.GlobalConstants;
import jmind.base.util.RequestUtil;
import jmind.core.cache.support.StatsCounterCache;
import jmind.core.log.LogUtil;
import jmind.core.spring.SpringBeanLocator;
import org.slf4j.Logger;

import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Map;

public abstract class HttpClient {

    protected final Logger logger = LogUtil.getLogger(getClass());
    public static final int SLOW_TIME = 200;
    private final StatsCounterCache statsCounter = new StatsCounterCache(1000);
    private static volatile HttpClient client = null;

    /**
     * 解决ipv6造成死锁问题
     * @see  http://www.th7.cn/Program/java/201511/677675.shtml
     *  -Djava.net.preferIPv4Stack=true
     */
    static {
        System.setProperty("java.net.preferIPv4Stack", "true");
    }

    public static HttpClient getHttpClient() {
        if (client == null) {
            synchronized (HttpClient.class) {
                if (client == null) {
                    client = createClient();
                }
            }

        }
        return client;
    }

    private static HttpClient createClient() {
        HttpClient client;
        try {
            Class.forName("org.apache.http.impl.nio.client.CloseableHttpAsyncClient");
            System.out.println("org.apache.http.impl.nio.client.CloseableHttpAsyncClient exists create PoolingHttpClient4");
            client = new PoolingHttpAsyncClient();
        } catch (Exception epp) {
            try {
                // 有4先用4,有连接池的
                Class.forName("org.apache.http.impl.client.CloseableHttpClient");
                try {
                    client = new PoolingHttpClient4();
                    System.out.println("org.apache.http.impl.client.CloseableHttpClient exists create PoolingHttpClient4");
                } catch (Exception e) {
                    client = new HttpClient4();
                    System.out.println("org.apache.http.impl.client.CloseableHttpClient exists create HttpClient4");
                }

            } catch (ClassNotFoundException e) {
                // 没4 用3
                try {
                    Class.forName("org.apache.commons.httpclient.HttpClient");
                    client = new HttpClient3();
                    System.out.println("org.apache.commons.httpclient.HttpClient exists create HttpClient3");
                } catch (ClassNotFoundException e1) {
                    client = new HttpDefault();
                    System.out.println(" create HttpDefault");
                }

            }
        }
        return client;
    }

    public StatsCounterCache getStatsCounter() {
        return statsCounter;
    }

    public static final String getURI(String url) {
        int i = url.indexOf("?");
        if (i > 0) {
            return url.substring(0, i);
        }
        return url;
    }

    final void success(long start, String url, String res) {
        long t;
        logger.debug("{}t={},url={},res={}", (t = System.currentTimeMillis() - start) > SLOW_TIME ? "slow|" : "", t,
                url, (res == null || res.length() < 500) ? res : res.substring(0, 500));
        statsCounter.mustGet(getURI(url)).recordSuccess(start, SLOW_TIME);

    }

    final void fail(long start, String url, Exception e) {
        logger.error(url, e);
        StatsCounter counter = statsCounter.mustGet(getURI(url));
        counter.recordException(start);
        if (SpringBeanLocator.getInstance().containsBean("httpRecord")) {
            Record record = SpringBeanLocator.getInstance().getBean("httpRecord", Record.class);
            record.ExceptionRecord(e, url, counter);
        }

    }

    /**
     * 根据url 取host
     *
     * @param url
     * @return
     */
    public static final String getHost(String url) {
        if (!DataUtil.isEmpty(url)) {
            try {
                URL domain = new URL(url);
                String host = domain.getHost();
                return host;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return DataUtil.EMPTY;
    }

    /**
     * get请求
     *
     * @param url
     * @return
     */
    public String get(String url) {
        return get(url, GlobalConstants.UTF8, 0,null);
    }

    public String get(String url, Map<String, ?> params) {
        String queryString = RequestUtil.toQueryString(params);
        return get(url + "?" + queryString);
    }


    public abstract String get(String url, String code, int timeout,Map<String, String> headers);

    public String post(String url, Map<String, String> params) {
        return post(url, params, GlobalConstants.UTF8, 0,null);
    }

    public abstract String post(String url, Map<String, String> params, String code, int timeout,Map<String,String> headers);

    /**
     * @param url
     * @param params  参数不用map 是因为参数名可能重复
     * @param code
     * @param timeout 0 不设置
     * @return
     */
    public abstract String post(String url, List<Pair<String, String>> params, String code, int timeout,Map<String,String> headers);

    /**
     * 直接把内容写到RequestBody里面，其实也支持post参数形式
     * @param url
     * @param body
     * @return
     */
    public  String postBody(String url, String body){
        return postBody(url, body,null);
    }

    public abstract String postBody(String url, String body,Map<String, String> headers);

    /**
     * 上传文件
     *
     * @param url      请求url
     * @param params   参数
     * @param fileName file参数名
     * @param file     文件
     * @return
     */
    public abstract String postFile(String url, Map<String, ?> params, String fileName, File file, String code);

    public abstract String postFile(String url, Map<String, ?> params, List<Pair<String, File>> files, String code);
}
